package com.loongtech.bi.manager.game;

import com.loongtech.bi.action.PageHelper;
import com.loongtech.bi.action.game.InstanceGameAction;
import com.loongtech.bi.entity.game.EntityActiveRoleInstanceStatusRoleNum;
import com.loongtech.bi.entity.game.EntityActiveRoleInstanceStatusTimes;
import com.loongtech.bi.entity.game.EntityActiveRoleInstanceStay;
import com.loongtech.bi.entity.game.EntityNewRoleSecondLossInstanceStay;
import com.loongtech.bi.manager.system.GameParamConfigManager;
import com.loongtech.bi.support.chart.ChartData1;
import com.loongtech.bi.support.chart.ChartFlow;
import com.loongtech.bi.support.chart.ChartSelect;
import com.loongtech.core.jpa.manager.ManagerQueryCacheBase;
import com.loongtech.core.util.Time;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.Map.Entry;

/**
 * 副本分析-manager
 * 
 */
@Service
public class InstanceGameManager extends ManagerQueryCacheBase<Object> {
	private static final long serialVersionUID = 1L;
	
	@Autowired
	ActiveRoleInstanceStatusRoleNumManager activeRoleInstanceStatusRoleNumManager;
	@Autowired
	ActiveRoleInstanceStatusTimesManager activeRoleInstanceStatusTimesManager;
    @Autowired
    private ActiveRole1LevelDistributeManager activeRole1LevelDistributeManager;
	@Autowired
	private ActiveRoleInstanceStayManager activeRoleInstanceStayManager;
	@Autowired
	private NewRoleSecondLossInstanceStayManager newRoleSecondLossInstanceStayManager;
	
	/**
	 *  参与率
	 * @param dateStart
	 * @param dateEnd
	 * @param queryPlatform
	 * @param queryChannel
	 * @param queryServer
	 * @return
	 */
	public List<InstancePlayRadio> getInstancePlayRadios(Date dateStart, Date dateEnd, String queryPlatform, String queryChannel, String queryServer, List<Integer> queryInstanceName, Map<String, Map<String, Integer>> levelNumTemp) {
		if (InstanceGameAction.instanceOpenLevel == null || InstanceGameAction.instanceOpenLevel.size() <= 1) {  // 开启等级没配，直接返回
			System.out.println("副本开启等级没配！");
			return null;
		}
		
		List<EntityActiveRoleInstanceStatusRoleNum> activeRoleInstanceStatusRoleNum = activeRoleInstanceStatusRoleNumManager.getActiveRoleInstanceStatusRoleNum(dateStart, dateEnd, queryPlatform, queryChannel, queryServer, queryInstanceName);
		if (activeRoleInstanceStatusRoleNum == null || activeRoleInstanceStatusRoleNum.size() <= 0) {
			System.out.println("active_role_instance_status_rolenum为空");
			return null;
		}
		
		List<EntityActiveRoleInstanceStatusTimes> activeRoleInstanceStatusTimes = activeRoleInstanceStatusTimesManager.getActiveRoleInstanceStatusTimes(dateStart, dateEnd, queryPlatform, queryChannel, queryServer, queryInstanceName);
		if (activeRoleInstanceStatusTimes == null || activeRoleInstanceStatusTimes.size() <= 0) {
			System.out.println("active_role_instance_status_times为空");
			return null;
		}
		
		Map<String, Map<String, Map<String, InstancePlayRadio>>> resultMap = new HashMap<>();  // 时间={副本ID={副本状态=InstancePlayRadio}}
		
		// 求出activeRoleInstanceStatusRoleNum中包含的各个指标
		for (EntityActiveRoleInstanceStatusRoleNum e : activeRoleInstanceStatusRoleNum) {
			String dateStr = Time.getDateStr(e.getDay());
			String instanceId = e.getInstancetid() + "";
			String status = e.getStatus() + "";
			
			if (!InstanceGameAction.instanceOpenLevel.containsKey(instanceId)) {  // 没配开启等级
				System.out.println("没有配开启等级：副本ID=" + instanceId);
				continue;
			}
			
			Map<String, Map<String, InstancePlayRadio>> tmp1 = resultMap.get(dateStr);
			if (tmp1 == null) {
				tmp1 = new HashMap<>();
				resultMap.put(dateStr, tmp1);
			}
			Map<String, InstancePlayRadio> tmp2 = tmp1.get(instanceId);
			if (tmp2 == null) {
				tmp2 = new HashMap<>();
				tmp1.put(instanceId, tmp2);
			}
			InstancePlayRadio tmp3 = new InstancePlayRadio();
			tmp3.setDateStr(Time.getDateStr(e.getDay())); // 日期
			tmp3.setInstanceId(instanceId); // 副本ID
			tmp3.setInstanceName(InstanceGameAction.instanceName.get(instanceId) == null ? instanceId : InstanceGameAction.instanceName.get(instanceId)); // 副本名称
			tmp3.setInstanceType(InstanceGameAction.instanceType.get(instanceId) == null ? instanceId : InstanceGameAction.instanceType.get(instanceId)); // 副本类型
			tmp3.setInstanceStatus(status);
			tmp3.setOpenLevel(Integer.parseInt(InstanceGameAction.instanceOpenLevel.get(instanceId))); // 开启等级
			//tmp2.setOkUserNum(1); // 满足条件角色数
			tmp3.setPlayUserNum(e.getRolenum()); // 参与角色数
			//tmp2.setPlayRadio(tmp2.getPlayUserNum() == 0 ? 0 : PageHelper.floatKeepTwoNumber(tmp2.getPlayUserNum() * 1.0 / tmp2.getPlayUserNum())); // 参与次数
			//tmp2.setOkPlayTimes(1); // 成功次数
			//tmp2.setOkRadio(tmp2.getOkPlayTimes() * 1.0 / 1);  // 成功率
			//private int avgPlayTimes; // 人均次数 playTimes / playUserNum
			//private int avgTime; // 平均完成时间
			tmp2.put(status, tmp3);
		}
		
		// 求出activeRoleInstanceStatusTimes中包含的各个指标
		for (EntityActiveRoleInstanceStatusTimes e : activeRoleInstanceStatusTimes) {
			String dateStr = Time.getDateStr(e.getDay());
			String instanceId = e.getInstancetid() + "";
			String status = e.getStatus() + "";
			
			Map<String, Map<String, InstancePlayRadio>> tmp0 = resultMap.get(dateStr);
			if (tmp0 == null) {
				continue;
			}
			Map<String, InstancePlayRadio> tmp1 = tmp0.get(instanceId);
			if (tmp1 == null) {
				continue;
			}
			InstancePlayRadio tmp2 = tmp1.get(status);
			if (tmp2 == null) {
				continue;
			}
			tmp2.setAvgTime(e.getSumpasstime());  // 平均时间
			tmp2.setPlayTimes(e.getTimes());  // 总次数
		}
		
		Map<String, InstancePlayRadio> resultMap2 = new LinkedHashMap<>();
		// 整理数据
		for (Entry<String, Map<String, Map<String, InstancePlayRadio>>> entry : resultMap.entrySet()) {
			String dateStr = entry.getKey();
			Map<String, Map<String, InstancePlayRadio>> value = entry.getValue();
			
			Map<String, Integer> okUserMap = levelNumTemp.get(dateStr);
			
			for (Entry<String, Map<String, InstancePlayRadio>> entry1 : value.entrySet()) {
				String instanceid = entry1.getKey();
				Map<String, InstancePlayRadio> value1 = entry1.getValue();

				int okusernum = (okUserMap == null || InstanceGameAction.instanceOpenLevel.get(instanceid) == null) ? 0 : okUserMap.get(InstanceGameAction.instanceOpenLevel.get(instanceid));

				for (Entry<String, InstancePlayRadio> entry2 : sortMapByKey(value1).entrySet()) {
					String instancestatus = entry2.getKey();
					InstancePlayRadio v = entry2.getValue();
					
					InstancePlayRadio t = resultMap2.get(dateStr + "-" + instanceid);
					if (t == null) {
						t = new InstancePlayRadio();
						t.setDateStr(dateStr);
						t.setInstanceId(v.getInstanceId());
						t.setInstanceName(v.getInstanceName());
						t.setInstanceType(v.getInstanceType());
						t.setOpenLevel(v.getOpenLevel());
						t.setOkUserNum(okusernum);
						
						resultMap2.put(dateStr + "-" + instanceid, t);
					}
					if (instancestatus.equals(InstanceGameAction.instance_join_status)) {  // 参与副本
						 t.setPlayUserNum(v.getPlayUserNum());
						 t.setPlayRadio(t.getOkUserNum() == 0 ? 0 : PageHelper.floatKeep4Number(t.getPlayUserNum() * 1.0 / t.getOkUserNum()));
						 t.setPlayTimes(v.getPlayTimes());
                         t.setAvgPlayTimes(t.getPlayTimes() == 0 ? 0 : (int)Math.round(t.getPlayTimes() * 1.0 / t.getPlayUserNum()));
					} else if (instancestatus.equals(InstanceGameAction.instance_pass_status)) {  // 完成副本
						t.setOkPlayTimes(v.getPlayTimes());
						t.setOkRadio(t.getPlayTimes() == 0 ? 0 : PageHelper.floatKeep4Number(t.getOkPlayTimes() * 1.0 / t.getPlayTimes()));
                        t.setAvgTime(t.getPlayTimes() == 0 ? 0 : PageHelper.floatKeep4Number(v.getAvgTime() / 60.0 / t.getOkPlayTimes()));
					}
				}
				
			}
		}
		
		ArrayList<InstancePlayRadio> result = new ArrayList<>(resultMap2.values());
		Collections.sort(result, new InstancePlayRadio().comparatorDate);
		
		return result;
	}

    private Map<String, InstancePlayRadio> sortMapByKey(Map<String, InstancePlayRadio> oriMap) {
        if (oriMap == null || oriMap.isEmpty()) {
            return null;
        }
        Map<String, InstancePlayRadio> sortedMap = new TreeMap<>(new Comparator<String>() {
            public int compare(String key1, String key2) {
                int intKey1 = 0, intKey2 = 0;
                try {
                    intKey1 = Integer.parseInt(key1);
                    intKey2 = Integer.parseInt(key2);
                } catch (Exception e) {
                    intKey1 = 0;
                    intKey2 = 0;
                }
                return intKey1 - intKey2;
            }});
        sortedMap.putAll(oriMap);
        return sortedMap;
    }

    /**
	 * 活跃用户停留率
	 * @param dateStart
	 * @param dateEnd
	 * @param queryPlatform
	 * @param queryChannel
	 * @param queryServer
	 * @return
	 */
	public List<InstanceStayActiveRadio> getInstanceStayActiveRadios(Date dateStart, Date dateEnd, String queryPlatform, String queryChannel, String queryServer, List<Integer> queryInstanceName, Map<String, Map<String, Integer>> levelNumTemp) {
		List<InstanceStayActiveRadio> result = new ArrayList<>();
		
		// stay
		List<EntityActiveRoleInstanceStay> datas = activeRoleInstanceStayManager.getActiveRoleInstanceStay(dateStart, dateEnd, queryPlatform, queryChannel, queryServer, queryInstanceName);
		for (EntityActiveRoleInstanceStay e : datas) {
			String dateStr = Time.getDateStr(e.getDay());
			String instanceid = e.getInstancetid() + "";
			
			Map<String, Integer> okUserMap = levelNumTemp.get(dateStr);
			int okusernum = (okUserMap == null || InstanceGameAction.instanceOpenLevel.get(instanceid) == null) ? 0 : okUserMap.get(InstanceGameAction.instanceOpenLevel.get(instanceid));
			
			InstanceStayActiveRadio i = new InstanceStayActiveRadio();
			i.setDateStr(dateStr);
			i.setInstanceId(instanceid);
			i.setInstanceName(InstanceGameAction.instanceName.get(instanceid) == null ? instanceid : InstanceGameAction.instanceName.get(instanceid)); // 副本名称
			i.setInstanceType(InstanceGameAction.instanceType.get(instanceid) == null ? instanceid : InstanceGameAction.instanceType.get(instanceid)); // 副本类型
			i.setActiveUserNum(okusernum);
			i.setStayUserNum(e.getRolenum());
			i.setActiveStayRadio(i.getActiveUserNum() == 0 ? 0 : PageHelper.floatKeep4Number(i.getStayUserNum() * 1.0 / i.getActiveUserNum()));
			
			result.add(i);
		}
		
		Collections.sort(result, new InstanceStayActiveRadio().comparatorDate);
		
		return result;
	}
	
	/**
	 * 新增次日流失用户停留率
	 * @param dateStart
	 * @param dateEnd
	 * @param queryPlatform
	 * @param queryChannel
	 * @param queryServer
	 * @return
	 */
	public List<InstanceStayLossRadio> getInstanceStayLossRadios(Date dateStart, Date dateEnd, String queryPlatform, String queryChannel, String queryServer, List<Integer> queryInstanceName, Map<String, Map<String, Integer>> levelNumTemp) {
		List<InstanceStayLossRadio> result = new ArrayList<>();
		
		// stay
		List<EntityNewRoleSecondLossInstanceStay> datas = newRoleSecondLossInstanceStayManager.getNewRoleSecondLossInstanceStay(dateStart, dateEnd, queryPlatform, queryChannel, queryServer, queryInstanceName);
		for (EntityNewRoleSecondLossInstanceStay e : datas) {
			String dateStr = Time.getDateStr(e.getDay());
			String instanceid = e.getInstancetid() + "";
			
			Map<String, Integer> okUserMap = levelNumTemp.get(dateStr);
			int okusernum = (okUserMap == null || InstanceGameAction.instanceOpenLevel.get(instanceid) == null) ? 0 : okUserMap.get(InstanceGameAction.instanceOpenLevel.get(instanceid));
			
			InstanceStayLossRadio i = new InstanceStayLossRadio();
			i.setDateStr(dateStr);
			i.setInstanceId(instanceid);
			i.setInstanceName(InstanceGameAction.instanceName.get(instanceid) == null ? instanceid : InstanceGameAction.instanceName.get(instanceid)); // 副本名称
			i.setInstanceType(InstanceGameAction.instanceType.get(instanceid) == null ? instanceid : InstanceGameAction.instanceType.get(instanceid)); // 副本类型
			i.setLossUserNum(okusernum);
			i.setStayUserNum(e.getRolenum());
			i.setLossStayRadio(i.getLossUserNum() == 0 ? 0 : PageHelper.floatKeep4Number(i.getStayUserNum() * 1.0 / i.getLossUserNum()));
			
			result.add(i);
		}
		
		Collections.sort(result, new InstanceStayLossRadio().comparatorDate);
		
		return result;
	}

    public Map<String, Map<String, Integer>> getAllUserByLevel(Date dateStart, Date dateEnd, String queryPlatform, String queryChannel, String queryServer) {
        // 求各个日期的满足条件的各个级别的用户数
        Map<String, Map<String, Integer>> levelNumTemp = new HashMap<>();  // dateStr={levelStr=num}
        Set<Integer> levels = new HashSet<>();
        int minLevel = Integer.MAX_VALUE;
        for (Entry<String, String> entry : InstanceGameAction.instanceOpenLevel.entrySet()) {
            if (!GameParamConfigManager.ALL_FLAT.equals(entry.getKey())) {
                int l = Integer.parseInt(entry.getValue());
                levels.add(l);
                if (minLevel > l) {
                    minLevel = l;
                }
            }
        }
        List<Object[]> levelList = activeRole1LevelDistributeManager.getAllKindRoleNumberGroupByLevel(dateStart, dateEnd, queryPlatform, queryChannel, queryServer, minLevel);
        for(Object[] o : levelList) {
            String dateStr = o[0].toString();
            String levelStr = o[1].toString();
            int levelInt = Integer.parseInt(levelStr);
            int num = Integer.parseInt(o[2].toString());

            Map<String, Integer> levelTemp = levelNumTemp.get(dateStr);
            if (levelTemp == null) {
                levelTemp = new HashMap<>();
                levelNumTemp.put(dateStr, levelTemp);

                for (int i : levels) {
                    levelTemp.put(i + "", 0);
                }
            }
            for (Map.Entry<String, Integer> entry : levelTemp.entrySet()) {
                if (Integer.parseInt(entry.getKey()) <= levelInt) {
                    levelTemp.put(entry.getKey(), entry.getValue() + num);
                }
            }
        }

        System.out.println("levelNumTemp-----------------begin");
        for(Entry<String, Map<String, Integer>> entry : levelNumTemp.entrySet()) {
            System.out.println(entry.getKey());
            for (Entry<String, Integer> ee : entry.getValue().entrySet()) {
                System.out.println(ee.getKey() + "  ------  " + ee.getValue());
            }
        }
        System.out.println("levelNumTemp-----------------end");

        return levelNumTemp;
    }

	// 副本参与率数据类
	public class InstancePlayRadio {
		private String dateStr; // 日期
		private String instanceType; // 副本类型
		private String instanceId; // 副本ID
		private String instanceName; // 副本名称
		private String instanceStatus;  // 副本状态
		private int openLevel; // 开启等级
		private int okUserNum; // 满足条件角色数
		private int playUserNum; // 参与角色数
		private double playRadio; // 参与率
		private int playTimes; // 参与次数
		private int okPlayTimes; // 成功次数
		private double okRadio; // 成功率
		private int avgPlayTimes; // 人均次数 playTimes / playUserNum
		private double avgTime; // 平均完成时间
		
		// 根据日期排序的比较器
		public final Comparator<InstancePlayRadio> comparatorDate = new Comparator<InstancePlayRadio>() {
			public int compare(InstancePlayRadio s1, InstancePlayRadio s2) {
				return s2.getDateStr().compareTo(s1.getDateStr());
			}
		};

		public String getDateStr() {
			return dateStr;
		}

		public void setDateStr(String dateStr) {
			this.dateStr = dateStr;
		}

		public String getInstanceType() {
			return instanceType;
		}

		public void setInstanceType(String instanceType) {
			this.instanceType = instanceType;
		}

		public String getInstanceId() {
			return instanceId;
		}

		public void setInstanceId(String instanceId) {
			this.instanceId = instanceId;
		}

		public int getOpenLevel() {
			return openLevel;
		}

		public void setOpenLevel(int openLevel) {
			this.openLevel = openLevel;
		}

		public int getOkUserNum() {
			return okUserNum;
		}

		public void setOkUserNum(int okUserNum) {
			this.okUserNum = okUserNum;
		}

		public int getPlayUserNum() {
			return playUserNum;
		}

		public void setPlayUserNum(int playUserNum) {
			this.playUserNum = playUserNum;
		}

		public double getPlayRadio() {
			return playRadio;
		}

		public void setPlayRadio(double playRadio) {
			this.playRadio = playRadio;
		}

		public int getPlayTimes() {
			return playTimes;
		}

		public void setPlayTimes(int playTimes) {
			this.playTimes = playTimes;
		}

		public int getOkPlayTimes() {
			return okPlayTimes;
		}

		public void setOkPlayTimes(int okPlayTimes) {
			this.okPlayTimes = okPlayTimes;
		}

		public double getOkRadio() {
			return okRadio;
		}

		public void setOkRadio(double okRadio) {
			this.okRadio = okRadio;
		}

		public int getAvgPlayTimes() {
			return avgPlayTimes;
		}

		public void setAvgPlayTimes(int avgPlayTimes) {
			this.avgPlayTimes = avgPlayTimes;
		}

		public double getAvgTime() {
			return avgTime;
		}

		public void setAvgTime(double avgTime) {
			this.avgTime = avgTime;
		}

		public String getInstanceName() {
			return instanceName;
		}

		public void setInstanceName(String instanceName) {
			this.instanceName = instanceName;
		}

		public String getInstanceStatus() {
			return instanceStatus;
		}

		public void setInstanceStatus(String instanceStatus) {
			this.instanceStatus = instanceStatus;
		}
	}
	
	// 活跃用户停留率数据类图表类
	public class InstanceStayActiveRadio {
		private String dateStr; // 日期
		private String instanceType; // 副本类型
		private String instanceId; // 副本ID
		@ChartFlow(name = "副本名称")
		private String instanceName; // 副本名称
		private int stayUserNum; // 停留角色数
		private int activeUserNum; // 活跃角色数
		@ChartSelect(name = "活跃停留率", key = 1)
		@ChartData1(name = "活跃停留率", key = 1)
		private double activeStayRadio; // 活跃停留率

		// 根据日期排序的比较器
		public final Comparator<InstanceStayActiveRadio> comparatorDate = new Comparator<InstanceStayActiveRadio>() {
			public int compare(InstanceStayActiveRadio s1, InstanceStayActiveRadio s2) {
				return s2.getDateStr().compareTo(s1.getDateStr());
			}
		};

        public final Comparator<InstanceStayActiveRadio> comparatorRadio = new Comparator<InstanceStayActiveRadio>() {
            public int compare(InstanceStayActiveRadio s1, InstanceStayActiveRadio s2) {
                return Double.valueOf(s1.getActiveStayRadio()).compareTo(Double.valueOf(s2.getActiveStayRadio()));
            }
        };
		
		public String getDateStr() {
			return dateStr;
		}

		public void setDateStr(String dateStr) {
			this.dateStr = dateStr;
		}

		public String getInstanceType() {
			return instanceType;
		}

		public void setInstanceType(String instanceType) {
			this.instanceType = instanceType;
		}

		public String getInstanceId() {
			return instanceId;
		}

		public void setInstanceId(String instanceId) {
			this.instanceId = instanceId;
		}

		public String getInstanceName() {
			return instanceName;
		}

		public void setInstanceName(String instanceName) {
			this.instanceName = instanceName;
		}

		public int getStayUserNum() {
			return stayUserNum;
		}

		public void setStayUserNum(int stayUserNum) {
			this.stayUserNum = stayUserNum;
		}

		public int getActiveUserNum() {
			return activeUserNum;
		}

		public void setActiveUserNum(int activeUserNum) {
			this.activeUserNum = activeUserNum;
		}

		public double getActiveStayRadio() {
			return activeStayRadio;
		}

		public void setActiveStayRadio(double activeStayRadio) {
			this.activeStayRadio = activeStayRadio;
		}
	}
	
	// 新增次日流失用户停留率数据类图表类
	public class InstanceStayLossRadio {
		private String dateStr; // 日期
		private String instanceType; // 副本类型
		private String instanceId; // 副本ID
		@ChartFlow(name = "副本名称")
		private String instanceName; // 副本名称
		private int stayUserNum; // 停留角色数
		private int lossUserNum; // 活跃角色数
		@ChartSelect(name = "新增次日流失率", key = 1)
		@ChartData1(name = "新增次日流失率", key = 1)
		private double lossStayRadio; // 新增次日流失率
		
		// 根据日期排序的比较器
		public final Comparator<InstanceStayLossRadio> comparatorDate = new Comparator<InstanceStayLossRadio>() {
			public int compare(InstanceStayLossRadio s1, InstanceStayLossRadio s2) {
				return s2.getDateStr().compareTo(s1.getDateStr());
			}
		};

        // 根据日期排序的比较器
        public final Comparator<InstanceStayLossRadio> comparatorRadio = new Comparator<InstanceStayLossRadio>() {
            public int compare(InstanceStayLossRadio s1, InstanceStayLossRadio s2) {
                return Double.valueOf(s1.getLossStayRadio()).compareTo(Double.valueOf(s2.getLossStayRadio()));
            }
        };

		public String getDateStr() {
			return dateStr;
		}

		public void setDateStr(String dateStr) {
			this.dateStr = dateStr;
		}

		public String getInstanceType() {
			return instanceType;
		}

		public void setInstanceType(String instanceType) {
			this.instanceType = instanceType;
		}

		public String getInstanceId() {
			return instanceId;
		}

		public void setInstanceId(String instanceId) {
			this.instanceId = instanceId;
		}

		public String getInstanceName() {
			return instanceName;
		}

		public void setInstanceName(String instanceName) {
			this.instanceName = instanceName;
		}

		public int getStayUserNum() {
			return stayUserNum;
		}

		public void setStayUserNum(int stayUserNum) {
			this.stayUserNum = stayUserNum;
		}

		public int getLossUserNum() {
			return lossUserNum;
		}

		public void setLossUserNum(int lossUserNum) {
			this.lossUserNum = lossUserNum;
		}

		public double getLossStayRadio() {
			return lossStayRadio;
		}

		public void setLossStayRadio(double lossStayRadio) {
			this.lossStayRadio = lossStayRadio;
		}
	}
}
